home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d12 / du.arc / FSINFO.C < prev    next >
C/C++ Source or Header  |  1990-10-05  |  8KB  |  276 lines

  1. /* @(#) fsinfo.c 1.2 90/09/08 14:38:57 */
  2.  
  3. /*
  4.  * Package:    du - Enhanced "du" disk usage report generator.
  5.  * File:    fsinfo.c - File-system information routines.
  6.  *
  7.  * The following routines are to provide the filesystem-specific support:
  8.  *
  9.  *   fs_initinfo() - Initializes internal filesystem tables.
  10.  *   fs_getinfo() - Get filesystem information for an entry.
  11.  *   fs_linkdone() - Determines whether a file has been visited already.
  12.  *   fs_numblocks() - Calculates disk usage of an entry.
  13.  *
  14.  * A linked list of (struct fsinfo) is maintained, one element per mounted
  15.  * filesystem.  The "fs_initinfo()" routine initializes this list.  The
  16.  * "fs_getinfo()" routine locates the element associated with the filesystem
  17.  * containing a particular file.  To minimize overhead, the "fs_getinfo()"
  18.  * routine should be called only when we change directories, and the
  19.  * information on the current directory should be used for all the items
  20.  * in that directory.  The "fs_linkdone()" and "fs_numblocks()" routines
  21.  * require the pointer returned by "fs_getinfo()".
  22.  *
  23.  * Sat Sep  8 14:34:56 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
  24.  *    Cleanup for distribution.
  25.  * Tue Apr 17 21:50:58 1990 - Chip Rosenthal <chip@chinacat.Unicom.COM>
  26.  *    Original composition.
  27.  *
  28.  * Copyright 1990, Unicom Systems Development.  All rights reserved.
  29.  * See accompanying README file for terms of distribution and use.
  30.  */
  31.  
  32. #include <stdio.h>
  33. #include <sys/types.h>
  34. #include <sys/stat.h>
  35. #include <sys/statfs.h>
  36. #include <mnttab.h>
  37. #include "du.h"
  38.  
  39. static char SccsID[] = "@(#) fsinfo.c 1.2 90/09/08 14:38:57";
  40.  
  41. /*
  42.  * Mount table stuff.
  43.  */
  44. #ifndef PNMNTTAB
  45. #   define PNMNTTAB "/etc/mnttab"
  46. #endif
  47. #ifndef ISMNTFREE
  48. #   define ISMNTFREE(m) ( (m)->mt_dev[0] == '\0' )
  49. #endif
  50. #ifdef BROKE_MNTTAB            /* ISC 2.0.2 botched <mnttab.h> */
  51. #   define mnttab mnttab_kludge
  52.     struct mnttab_kludge {
  53.     char mt_dev[32];
  54.     char mt_filsys[32];
  55.     char mt_stuff[12];
  56.     };
  57. #endif
  58.  
  59. /*
  60.  * The head of a linked list list of filesystem information records.
  61.  */
  62. struct fsinfo *Fsinfo_list;
  63.  
  64. /*
  65.  * External procedures.
  66.  */
  67. extern void *memset();
  68.  
  69.  
  70. /*
  71.  * fs_initinfo() - Initializes list of filesystem information.
  72.  */
  73. void fs_initinfo()
  74. {
  75.     struct fsinfo    *fsp, *fsp_tail;
  76.     struct mnttab    mbuf;
  77.     struct stat        sbuf;
  78.     struct statfs    fsbuf;
  79.     FILE        *fp;
  80.     int            n;
  81.  
  82.     Fsinfo_list = fsp_tail = NULL;
  83.  
  84.     /*
  85.      * Open up the mount table.
  86.      */
  87.     if ( (fp=fopen(PNMNTTAB,"r")) == NULL )
  88.     errmssg(ERR_ABORT,"couldn't open '%s'", PNMNTTAB);
  89.  
  90.     /*
  91.      * Go through mount table and look for all mounted filesystems.
  92.      */
  93.     while ( fread( (char *)&mbuf, sizeof(struct mnttab), 1, fp ) == 1 ) {
  94.  
  95.     /*
  96.      * Ignore empty slots.
  97.      */
  98.     if ( ISMNTFREE(&mbuf) )
  99.         continue;
  100.  
  101.     /*
  102.      * Get the information on this filesystem.
  103.      */
  104.     if ( stat(mbuf.mt_filsys,&sbuf) != 0 ) {
  105.         errmssg(ERR_WARN,"couldn't stat '%s'", mbuf.mt_filsys);
  106.         continue;
  107.     }
  108.     if ( statfs(mbuf.mt_filsys,&fsbuf,sizeof(struct statfs),0) != 0 ) {
  109.         errmssg(ERR_WARN,"couldn't statfs '%s'", mbuf.mt_filsys);
  110.         continue;
  111.     }
  112.  
  113.     /*
  114.      * Allocate the filesystem information structure.
  115.      */
  116.     fsp = (struct fsinfo *) xmalloc( sizeof(struct fsinfo) );
  117.     fsp->dev = sbuf.st_dev;
  118.     fsp->nino = fsbuf.f_files;
  119.     fsp->bsize = fsbuf.f_bsize;
  120.     fsp->nindir = fsp->bsize / sizeof(daddr_t);
  121.     fsp->next = NULL;
  122.  
  123.     /*
  124.      * Create the bit vector which indicates multiply-linked inodes done.
  125.      *   See fs_linkdone() for information on this bitvector.
  126.      */
  127.     n = fsp->nino/8 + 1;
  128.     fsp->idone = (unsigned char *) xmalloc((unsigned)n);
  129.     memset(fsp->idone,0,n);
  130.  
  131.     /*
  132.      * Attach the filesystem information to the end of the list.
  133.      */
  134.     if ( Fsinfo_list == NULL )
  135.         Fsinfo_list = fsp;
  136.     else
  137.         fsp_tail->next = fsp;
  138.     fsp_tail = fsp;
  139.  
  140.     }
  141.  
  142.     (void) fclose(fp);
  143.  
  144. }
  145.  
  146.  
  147. /*
  148.  * fs_getinfo() - Get filesystem information on a entry.
  149.  */
  150. struct fsinfo *fs_getinfo(fsp,sbufp)
  151. Reg struct fsinfo    *fsp;    /* filesystem info on dir containing entry    */
  152. Reg struct stat        *sbufp;    /* stat information on the entry          */
  153. {
  154.     /*
  155.      * If we already have info on the directory containing this entry and
  156.      * this entry doesn't cross a mount point, then we can use the same info.
  157.      */
  158.     if ( fsp != NULL && fsp->dev == sbufp->st_dev )
  159.     return fsp;
  160.  
  161.     /*
  162.      * Search the linked list for this filesystem.
  163.      */
  164.     fsp = Fsinfo_list;
  165.     while ( fsp != NULL && fsp->dev != sbufp->st_dev )
  166.     fsp = fsp->next;
  167.     return fsp;
  168. }
  169.  
  170.  
  171. /*
  172.  * fs_linkdone() - Determines whether a file has been visited already.
  173.  *
  174.  *   This procedure implements the logic to avoid recounting of multiply
  175.  *   linked files.  Each fsinfo structure contains a bit vector for all of
  176.  *   the filesystem's inodes.  This procedure uses this vector to see if
  177.  *   a file has been done already.  The first time this procedure is called
  178.  *   for a particular inode number, we return FALSE and mark it in the bit
  179.  *   vector.  All following times this procedure is called we return TRUE.
  180.  */
  181. int fs_linkdone(fsp,sbufp)
  182. Reg struct fsinfo *fsp;
  183. Reg struct stat *sbufp;
  184. {
  185.     Reg unsigned char *rowp;
  186.     int mask;
  187.  
  188.     /*
  189.      * Locate the bit within the vector for this inode.
  190.      */
  191.     rowp = fsp->idone + ( sbufp->st_ino >> 3 );
  192.     mask = 1 << (sbufp->st_ino & 07);
  193.  
  194.     /*
  195.      * If the bit is set then this link was already done.
  196.      */
  197.     if ( *rowp & mask )
  198.     return TRUE;
  199.  
  200.     /*
  201.      * Set the bit and indicate the link hasn't been done yet.
  202.      */
  203.     *rowp |= mask;
  204.     return FALSE;
  205. }
  206.  
  207.  
  208. #define DIRBLKS        10            /* num direct addrs in inode  */
  209. #define CEIL_DIV(A,B)  ( ((A)+(B)-1) / (B) )    /* calculate "ceiling(A/B)"   */
  210.  
  211. /*
  212.  * fs_numblocks() - Calculates disk usage of an entry.
  213.  */
  214. long fs_numblocks(fsp,sbufp)
  215. Reg struct fsinfo *fsp;
  216. struct stat *sbufp;
  217. {
  218.     Reg long    n_used;        /* num blocks used, incl overhead    */
  219.     Reg long    n_to_place;    /* num data blocks to be placed        */
  220.     long    n_single_ind;    /* scratch single indirect block cntr    */
  221.     long    n_double_ind;    /* scratch double indirect block cntr    */
  222.  
  223.     /*
  224.      * Determine the number of blocks which are required to store this file.
  225.      */
  226.     n_used = CEIL_DIV( sbufp->st_size , fsp->bsize );
  227.     n_to_place = n_used;
  228.  
  229.     /*
  230.      * The first DIRBLKS blocks are directly addressed through the inode.
  231.      */
  232.     n_to_place -= DIRBLKS;
  233.     if ( n_to_place <= 0 )
  234.     goto done;
  235.  
  236.     /*
  237.      * With the single indirect block, we can get another "nindir" blocks.
  238.      */
  239.     ++n_used;
  240.     n_to_place -= fsp->nindir;
  241.     if ( n_to_place <= 0 )
  242.     goto done;
  243.  
  244.     /*
  245.      * With the double indirect block, we can get another "nindir" single
  246.      * indirect blocks, for a total of another "nindir**2" data blocks.
  247.      */
  248.     n_single_ind = CEIL_DIV( n_to_place , fsp->nindir );
  249.     if ( n_single_ind > fsp->nindir )
  250.     n_single_ind = fsp->nindir;
  251.     n_used += 1 + n_single_ind;
  252.     n_to_place -= n_single_ind * fsp->nindir ;
  253.     if ( n_to_place <= 0 )
  254.     goto done;
  255.  
  256.     /*
  257.      * With the triple indirect block, we can get another "nindir" double
  258.      * indirect blocks, for another "nindir**2" single indirect blocks, for
  259.      * a total of another "nindir**3" data blocks.
  260.      */
  261.     n_single_ind = CEIL_DIV( n_to_place , fsp->nindir );
  262.     n_double_ind = CEIL_DIV( n_single_ind , fsp->nindir );
  263.     n_used += 1 + n_double_ind + n_single_ind;
  264.  
  265. done:
  266.  
  267.     /*
  268.      * Convert the usage from native blocksize to reporting blocksize.
  269.      */
  270.     if ( Report_blksize == 0 || Report_blksize == fsp->bsize )
  271.     return n_used;
  272.     else
  273.     return CEIL_DIV( n_used*fsp->bsize , Report_blksize );
  274. }
  275.  
  276.